package lol_stream_manager;

import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.io.File;
import javax.imageio.ImageIO;

public class SobelEdgeDetector {

    int[] input;
    int[] output;
    float[] template = {-1, 0, 1, -2, 0, 2, -1, 0, 1};
    int progress;
    int templateSize = 3;
    int width;
    int height;
    double[] direction;
    boolean isThresholded = false;
    int threasholdValue;
    boolean[][] bwEdgeRaster;

    public void sobel() {
        progress = 0;
    }

    public void init( BufferedImage image ) {
        width = image.getWidth();
        height = image.getHeight();
        int[] orig = new int[width*height];
        
        PixelGrabber grabber = new PixelGrabber(image, 0, 0, width, height, orig, 0, width);
        try{
            grabber.grabPixels();
        } catch ( InterruptedException ie ) {
            ie.printStackTrace();
        }
        
        input = new int[width * height];
        output = new int[width * height];
        direction = new double[width * height];
        input = orig;
    }

    public BufferedImage process() {
        float[] GY = new float[width * height];
        float[] GX = new float[width * height];
        int[] total = new int[width * height];
        progress = 0;
        int sum = 0;
        int max = 0;

        for (int x = (templateSize - 1) / 2; x < width - (templateSize + 1) / 2; x++) {
            progress++;
            for (int y = (templateSize - 1) / 2; y < height - (templateSize + 1) / 2; y++) {
                sum = 0;

                for (int x1 = 0; x1 < templateSize; x1++) {
                    for (int y1 = 0; y1 < templateSize; y1++) {
                        int x2 = (x - (templateSize - 1) / 2 + x1);
                        int y2 = (y - (templateSize - 1) / 2 + y1);
                        float value = (input[y2 * width + x2] & 0xff) * (template[y1 * templateSize + x1]);
                        sum += value;
                    }
                }
                GY[y * width + x] = sum;
                for (int x1 = 0; x1 < templateSize; x1++) {
                    for (int y1 = 0; y1 < templateSize; y1++) {
                        int x2 = (x - (templateSize - 1) / 2 + x1);
                        int y2 = (y - (templateSize - 1) / 2 + y1);
                        float value = (input[y2 * width + x2] & 0xff) * (template[x1 * templateSize + y1]);
                        sum += value;
                    }
                }
                GX[y * width + x] = sum;

            }
        }
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                total[y * width + x] = (int) Math.sqrt(GX[y * width + x] * GX[y * width + x] + GY[y * width + x] * GY[y * width + x]);
                direction[y * width + x] = Math.atan2(GX[y * width + x], GY[y * width + x]);
                if (max < total[y * width + x]) {
                    max = total[y * width + x];
                }
            }
        }
        float ratio = (float) max / 255;
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                sum = (int) (total[y * width + x] / ratio);
                output[y * width + x] = 0xff000000 | ((int) sum << 16 | (int) sum << 8 | (int) sum);
            }
        }
        progress = width;
        
        bwEdgeRaster = new boolean[height][width];
        int i=0, j=0;
        if( isThresholded )
            for(int x=0; x<output.length; x++){
                if( (output[x] & 0xff) >= threasholdValue ){
                        output[x]=0xffffffff; 
                        bwEdgeRaster[j][i] = true;
                }
                else {
                        output[x]=0xff000000;
                        bwEdgeRaster[j][i] = false;
                }
                i++;
                if( i == width ){
                    i = 0;
                    j++;
                }
            }

        Image edgeImage = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(width, height, output, 0, width));
        BufferedImage finalEdge = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        finalEdge.getGraphics().drawImage(edgeImage, 0, 0, null);

        return finalEdge;
    }

    public double[] getDirection() {
        return direction;
    }

    public int getProgress() {
        return progress;
    }
    
    public void setThreshold( int value ){
        isThresholded = true;
        threasholdValue = value;
    }

}